import socket
import websockets
import asyncio


# -------------------------- 1. 产品接口：统一的网络连接接口 --------------------------
# 所有类型的连接都实现这个接口，确保客户端用统一的方式调用（如连接、发送、关闭）
class NetworkConnection:
    def connect(self) -> bool:
        """建立连接：返回True表示连接成功，False失败"""
        raise NotImplementedError("子类必须实现connect方法")

    def send_data(self, data: bytes) -> bool:
        """发送数据：返回True表示发送成功"""
        raise NotImplementedError("子类必须实现send_data方法")

    def close(self) -> None:
        """关闭连接"""
        raise NotImplementedError("子类必须实现close方法")


# -------------------------- 2. 具体产品：不同协议的连接实现 --------------------------
# 具体产品1：TCP连接（用于硬件设备通信）
class TcpConnection(NetworkConnection):
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port
        self.socket = None  # 底层TCP socket对象

    def connect(self) -> bool:
        """TCP连接逻辑：创建socket、发起连接"""
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((self.host, self.port))
            print(f"TCP连接成功：{self.host}:{self.port}")
            return True
        except Exception as e:
            print(f"TCP连接失败：{e}")
            return False

    def send_data(self, data: bytes) -> bool:
        """TCP发送数据：基于流传输，需处理粘包（这里简化为直接发送）"""
        if not self.socket:
            print("TCP连接未建立，无法发送数据")
            return False
        try:
            self.socket.sendall(data)
            print(f"TCP发送成功：{len(data)}字节")
            return True
        except Exception as e:
            print(f"TCP发送失败：{e}")
            return False

    def close(self) -> None:
        """关闭TCP连接"""
        if self.socket:
            self.socket.close()
            self.socket = None
            print(f"TCP连接已关闭：{self.host}:{self.port}")


# 具体产品2：UDP连接（用于日志采集）
class UdpConnection(NetworkConnection):
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port
        self.socket = None  # 底层UDP socket对象

    def connect(self) -> bool:
        """UDP是无连接协议，这里模拟“逻辑连接”（初始化socket）"""
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            print(f"UDP socket初始化成功（目标：{self.host}:{self.port}）")
            return True
        except Exception as e:
            print(f"UDP socket初始化失败：{e}")
            return False

    def send_data(self, data: bytes) -> bool:
        """UDP发送数据：无连接，直接发送到目标地址"""
        if not self.socket:
            print("UDP socket未初始化，无法发送数据")
            return False
        try:
            self.socket.sendto(data, (self.host, self.port))
            print(f"UDP发送成功：{len(data)}字节（目标：{self.host}:{self.port}）")
            return True
        except Exception as e:
            print(f"UDP发送失败：{e}")
            return False

    def close(self) -> None:
        """关闭UDP socket"""
        if self.socket:
            self.socket.close()
            self.socket = None
            print("UDP socket已关闭")


# 具体产品3：WebSocket连接（用于前端实时通信）
class WsConnection(NetworkConnection):
    def __init__(self, url: str):
        self.url = url
        self.websocket = None  # 底层WebSocket对象
        self.loop = None  # asyncio事件循环（WebSocket依赖异步）

    def connect(self) -> bool:
        """WebSocket连接：基于异步协议，需启动事件循环"""
        try:
            self.loop = asyncio.get_event_loop()
            # 异步连接逻辑封装为同步调用
            self.websocket = self.loop.run_until_complete(websockets.connect(self.url))
            print(f"WebSocket连接成功：{self.url}")
            return True
        except Exception as e:
            print(f"WebSocket连接失败：{e}")
            return False

    def send_data(self, data: bytes) -> bool:
        """WebSocket发送数据（支持文本/二进制，这里用二进制）"""
        if not self.websocket or not self.loop:
            print("WebSocket连接未建立，无法发送数据")
            return False
        try:
            # 异步发送封装为同步调用
            self.loop.run_until_complete(self.websocket.send(data))
            print(f"WebSocket发送成功：{len(data)}字节")
            return True
        except Exception as e:
            print(f"WebSocket发送失败：{e}")
            return False

    def close(self) -> None:
        """关闭WebSocket连接"""
        if self.websocket and self.loop:
            self.loop.run_until_complete(self.websocket.close())
            self.websocket = None
            self.loop = None
            print(f"WebSocket连接已关闭：{self.url}")


# -------------------------- 3. 简单工厂：统一创建连接 --------------------------
class ConnectionFactory:
    @staticmethod
    def create_connection(conn_type: str, **kwargs) -> NetworkConnection:
        """
        创建网络连接实例
        :param conn_type: 连接类型（tcp/udp/ws）
        :param kwargs: 连接参数（如tcp需要host/port，ws需要url）
        :return: 对应的NetworkConnection实例
        """
        if conn_type.lower() == "tcp":
            # 校验TCP必要参数
            required_params = ["host", "port"]
            if not all(param in kwargs for param in required_params):
                raise ValueError("创建TCP连接需传入 host 和 port 参数")
            return TcpConnection(host=kwargs["host"], port=kwargs["port"])

        elif conn_type.lower() == "udp":
            # 校验UDP必要参数
            required_params = ["host", "port"]
            if not all(param in kwargs for param in required_params):
                raise ValueError("创建UDP连接需传入 host 和 port 参数")
            return UdpConnection(host=kwargs["host"], port=kwargs["port"])

        elif conn_type.lower() == "ws":
            # 校验WebSocket必要参数
            if "url" not in kwargs:
                raise ValueError("创建WebSocket连接需传入 url 参数")
            return WsConnection(url=kwargs["url"])

        else:
            raise ValueError(f"不支持的连接类型：{conn_type}（仅支持 tcp/udp/ws）")


# -------------------------- 4. 客户端代码：真实业务场景调用 --------------------------
if __name__ == "__main__":
    # 场景1：后端与硬件设备建立TCP连接，发送控制指令
    tcp_conn = ConnectionFactory.create_connection(
        conn_type="tcp",
        host="192.168.1.100",  # 硬件设备IP
        port=8080  # 硬件设备TCP端口
    )
    if tcp_conn.connect():
        tcp_conn.send_data(b"control: start_device")  # 发送二进制控制指令
        tcp_conn.close()

    print("-" * 50)

    # 场景2：后端向日志服务器发送UDP日志
    udp_conn = ConnectionFactory.create_connection(
        conn_type="udp",
        host="10.0.0.5",  # 日志服务器IP
        port=514  # 日志服务器UDP端口（标准syslog端口）
    )
    if udp_conn.connect():
        log_data = b"[INFO] 服务启动成功，时间：2024-05-20 10:30:00"
        udp_conn.send_data(log_data)  # 发送日志数据
        udp_conn.close()

    print("-" * 50)

    # 场景3：后端与前端实时页面建立WebSocket连接，推送实时数据
    ws_conn = ConnectionFactory.create_connection(
        conn_type="ws",
        url="ws://127.0.0.1:8765"  # 前端WebSocket服务地址
    )
    if ws_conn.connect():
        realtime_data = b'{"user_count": 128, "server_load": 0.35}'  # 实时数据（二进制JSON）
        ws_conn.send_data(realtime_data)
        ws_conn.close()